#include "common.hpp"

static const char *optString = "h?";

static const struct option longOpts[] = {
	{ "help", no_argument, NULL, 'h' },
	{ 0,0,0,0}
};

int main (int argc, char* const argv[]) {

	ipc::shared_memory_with_exceptions<size_t> vacias	( my_ftok(COUNTER|VACIAS));
	ipc::shared_memory_with_exceptions<size_t> llenas	( my_ftok(COUNTER|LLENAS));
	ipc::shared_memory_with_exceptions<size_t> tapadas	( my_ftok(COUNTER|TAPADAS));
//	ipc::shared_memory_with_exceptions<size_t> etiquetadas (my_ftok(COUNTER|ETIQUETADAS));
	ipc::shared_memory_with_exceptions<size_t> listas	( my_ftok(COUNTER|LISTAS));

	ipc::semaphore_with_exceptions mutex_vacias ( my_ftok(MUTEX|VACIAS),0);
	ipc::semaphore_with_exceptions mutex_llenas ( my_ftok(MUTEX|LLENAS),0);	
	ipc::semaphore_with_exceptions mutex_tapadas ( my_ftok(MUTEX|TAPADAS),0);
//	ipc::semaphore_with_exceptions mutex_etiquetadas ( my_ftok(MUTEX|ETIQUETADAS),0);
	ipc::semaphore_with_exceptions mutex_listas ( my_ftok(MUTEX|LISTAS),0);

	ipc::semaphore_vector mutex_llenadoras ( my_ftok(MUTEX|LLENADORA),MAX_LLENADORAS );
	ipc::semaphore_with_exceptions mutex_tapadora ( my_ftok(MUTEX|TAPADORA),0);
	ipc::semaphore_with_exceptions mutex_etiquetadora ( my_ftok(MUTEX|ETIQUETADORA),0);

	int longIndex = 0;
	int option = 0;
	bool ayuda = false;
	char orden;

	while ( (option = getopt_long(argc,argv,optString,longOpts,&longIndex) ) != EOF ) {
		switch (option) {
			case '?':
			case 'h':
			case ':':
				ayuda = true;
				break;
			default:
				break;
		}
	}

	if ( ayuda ) {
		std::cerr << "Proceso para preparación del entorno y ejecución." << std::endl;
		std::cerr << "\tUso: " << argv[0] << " [-h]" << std::endl;
		std::cerr << "\tParametros:" << std::endl;
		std::cerr << "\t\t-h,--help:\tMostrar este mensaje de ayuda." << std::endl;

		return (ayuda) ? 0 : -1;
	}

	try {
		mutex_vacias.get	 (PERMITS | IPC_CREAT|IPC_EXCL);
		vacias.get		 (PERMITS | IPC_CREAT|IPC_EXCL);
		(*vacias)=27;
		mutex_llenas.get	 (PERMITS | IPC_CREAT|IPC_EXCL);
		llenas.get		 (PERMITS | IPC_CREAT|IPC_EXCL);
		(*llenas)=0;
		mutex_tapadas.get	 (PERMITS | IPC_CREAT|IPC_EXCL);
		tapadas.get		 (PERMITS | IPC_CREAT|IPC_EXCL);
		(*tapadas)=0;
//		mutex_etiquetadas.get(PERMITS | IPC_CREAT|IPC_EXCL);
//		etiquetadas.get	 (PERMITS | IPC_CREAT|IPC_EXCL);
//		(*etiquetadas)=0;
		mutex_listas.get	 (PERMITS | IPC_CREAT|IPC_EXCL);
		listas.get		 (PERMITS | IPC_CREAT|IPC_EXCL);
		(*listas)=0;

		ipc::assert ( mutex_llenadoras.get	 (PERMITS | IPC_CREAT|IPC_EXCL) == 0, "get", mutex_llenadoras );
		mutex_tapadora.get	 (PERMITS | IPC_CREAT|IPC_EXCL);
		mutex_etiquetadora.get(PERMITS | IPC_CREAT|IPC_EXCL);

		// Maquinas.
		for (size_t i=0; i<MAX_LLENADORAS; ++i) {
			ipc::assert ( mutex_llenadoras.init(1,i) == 0, "init", mutex_llenadoras );
		}
		mutex_tapadora.init(0);
		mutex_etiquetadora.init(0);

		// Productos. Botellas en transito.
		mutex_vacias.init(1);
		mutex_llenas.init(1);
		mutex_tapadas.init(1);
//		mutex_etiquetadas.init(1);
		mutex_listas.init(1);

		const char* jugo = "5"; // dosis de jugo por llenadora. (5x5 = 25)
		const char* tapas = "23"; // cantidad de tapas en la tapadora.
		const char* etiquetas = "21"; // cantidad de etiquetas en la etiquetadora.

		// Activo las llenadoras.
		size_t llenadoras = (MAX_LLENADORAS > 5) ? 5 : MAX_LLENADORAS;
		for (size_t i=0; i<llenadoras; ++i) {
			if (fork() == 0)
				execlp("./llenadora","llenadora","-i",c_parse(i),"-r",jugo,(char*)NULL);
		}
		
		// Activo la tapadora.
		if (fork() == 0)
			execlp("./tapadora","tapadora","-r",tapas,(char*)NULL);

		// Activo la etiquetadora.
		if (fork() == 0)
			execlp("./etiquetadora","etiquetadora","-r",etiquetas,(char*)NULL);

	} catch (ipc::exception& e) {
		logger << "Lanzador: " << e.what() << "." << nl;
	}

	do
		std::cin >> orden;
	while ( (orden != 'q') && (orden != 'd') );

	if (orden == 'd') {
		pid_t destructor = fork();
		if (destructor == 0)
			execlp("./destructor","destructor",(char*)NULL);
		else
			waitpid(destructor,NULL,0);	
	}
	
	return 0;
}

